#include "debugger.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/user.h>

// 获取当前指令指针
static uint64_t get_instruction_pointer(pid_t pid) {
    struct user_regs_struct regs;
    if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1) {
        return 0;
    }
#ifdef __x86_64__
    return regs.rip;
#else
    return regs.eip;
#endif
}

// 获取符号地址
static uint64_t get_symbol_address(debugger_t *dbg, const char *symbol_name) {
    if (!dbg || !symbol_name) return 0;
    return debugger_resolve_symbol(dbg, symbol_name);
}

// 使用objdump进行反汇编
int disasm_using_objdump(debugger_t *dbg, uint64_t address, int num_instructions, const char *mode) {
    if (!dbg) return -1;
    
    // 创建临时文件来保存内存内容
    char temp_file[] = "/tmp/disasm_XXXXXX";
    int fd = mkstemp(temp_file);
    if (fd == -1) {
        printf("创建临时文件失败\n");
        return -1;
    }
    
    // 读取内存内容到临时文件
    uint64_t current_addr = address;
    unsigned char buffer[4096];
    size_t total_read = 0;
    
    for (int i = 0; i < num_instructions * 16 && total_read < sizeof(buffer); i += 8) {
        long result = ptrace(PTRACE_PEEKTEXT, dbg->pid, current_addr + i, NULL);
        if (result == -1) {
            break;
        }
        memcpy(buffer + total_read, &result, sizeof(result));
        total_read += sizeof(result);
    }
    
    if (total_read == 0) {
        printf("无法读取内存内容\n");
        close(fd);
        unlink(temp_file);
        return -1;
    }
    
    // 写入临时文件
    write(fd, buffer, total_read);
    close(fd);
    
    // 构建objdump命令
    char command[512];
    if (strcmp(mode, "function") == 0) {
        // 函数反汇编模式
        snprintf(command, sizeof(command), 
                 "objdump -D -b binary -m i386:x86-64 --adjust-vma=0x%lx -M intel %s 2>&1 | head -50",
                 address, temp_file);
    } else {
        // 地址反汇编模式
        snprintf(command, sizeof(command), 
                 "objdump -D -b binary -m i386:x86-64 --adjust-vma=0x%lx -M intel %s 2>&1 | head -%d",
                 address, temp_file, num_instructions + 5);
    }
    
    printf("=== 使用objdump反汇编地址 0x%lx 附近的指令 ===\n", address);
    printf("执行命令: %s\n", command);
    
    // 执行objdump命令
    FILE *fp = popen(command, "r");
    if (!fp) {
        printf("执行objdump命令失败\n");
        unlink(temp_file);
        return -1;
    }
    
    char line[256];
    int instruction_count = 0;
    int skip_header = 1;
    int has_output = 0;
    
    while (fgets(line, sizeof(line), fp) != NULL) {
        // 显示所有输出用于调试
        printf("objdump输出: %s", line);
        has_output = 1;
        
        // 跳过文件头信息
        if (skip_header) {
            if (strstr(line, "Disassembly of section") != NULL) {
                skip_header = 0;
            }
            continue;
        }
        
        // 跳过空行和节标题
        if (strlen(line) <= 1 || line[0] == ' ') {
            continue;
        }
        
        // 显示反汇编结果
        printf("%s", line);
        instruction_count++;
        
        if (instruction_count >= num_instructions && strcmp(mode, "function") != 0) {
            break;
        }
    }
    
    if (!has_output) {
        printf("objdump没有输出任何内容\n");
    }
    
    pclose(fp);
    unlink(temp_file);
    
    return 0;
}

// 反汇编指定地址的指令
int disasm_address(debugger_t *dbg, uint64_t address, int num_instructions) {
    return disasm_using_objdump(dbg, address, num_instructions, "address");
}

// 反汇编当前指令位置
int disasm_current(debugger_t *dbg, int num_instructions) {
    if (!dbg) return -1;
    
    uint64_t current_addr = get_instruction_pointer(dbg->pid);
    return disasm_address(dbg, current_addr, num_instructions);
}

// 反汇编指定函数
int disasm_function(debugger_t *dbg, const char *function_name) {
    if (!dbg || !function_name) return -1;
    
    // 获取函数地址
    uint64_t func_addr = get_symbol_address(dbg, function_name);
    if (func_addr == 0) {
        printf("无法找到函数 '%s' 的地址\n", function_name);
        return -1;
    }
    
    printf("函数 '%s' 的地址: 0x%lx\n", function_name, func_addr);
    return disasm_using_objdump(dbg, func_addr, 30, "function");
}